<?php

namespace tmcore\base;

use think\Container;
use think\helper\Str;
use tmcore\exceptions\SystemException;

abstract class BaseDriver
{
    /**
     * 驱动配置类型
     * @var string
     */
    protected string $name = '';

    /**
     * 配置
     * @var array
     */
    protected array $config = [];

    /**
     * 驱动
     * @var array
     */
    protected array $drivers = [];

    /**
     * 驱动的命名空间
     * @var string
     */
    protected string $namespace = '';

    /**
     * 初始化
     * @param string $name 驱动配置类型
     * @param array $config 配置
     */
    public function __construct($name = '', $config = [])
    {
        $this->name  = $name;
        $this->config = $config;
    }

    /**
     * 动态调用方法
     * @param string $method
     * @param array $parameters
     * @return mixed
     * @throws SystemException
     */
    public function __call($method, $parameters)
    {
        return $this->driver()->$method(...$parameters);
    }

    /**
     * 获取驱动实例
     * @return mixed
     * @throws SystemException
     */
    protected function driver()
    {
        $name = $this->name ?: $this->getDefaultDriver();
        if (!$name) throw new SystemException('default driver not exists:' . static::class, 118);

        $this->drivers[$name] = $this->drivers[$name] ?? $this->createDriver($name);

        return $this->drivers[$name];
    }

    /**
     * 创建驱动
     * @param string $name
     * @return mixed
     * @throws SystemException
     */
    protected function createDriver($name)
    {
        if(!$this->namespace) throw new SystemException('namespace not exists: ' . $this->namespace, 118);

        $class = $this->namespace . Str::studly($name);
        if (!class_exists($class)) throw new SystemException('class not exists: ' . $class, 118);

        // 依赖注入获取驱动实例
        $handle = Container::getInstance()->invokeClass($class, [$name, $this->config]);
        $this->config = [];
        return $handle;
    }

    /**
     * 默认驱动
     * @return string|null
     */
    abstract protected function getDefaultDriver();

}